// pages/rope/rope.js
const { QNMPPlugin, QNBleProtocols } = requirePlugin('QNBleApi');

const { RopeProtocol } = QNBleProtocols;

export function formatTime(date, fmt = 'YYYY-MM-DD HH:mm:ss') {
  if (date.toString() === 'Invalid Date') {
    // console.warn('[formatTime] Invalid Date');
    return '';
  }
  const o = {
    'M+': date.getMonth() + 1,
    'D+': date.getDate(),
    'h+': date.getHours() % 12 === 0 ? 12 : date.getHours() % 12,
    'H+': date.getHours(),
    'm+': date.getMinutes(),
    's+': date.getSeconds(),
    // 季度
    'q+': Math.floor((date.getMonth() + 3) / 3),
  };
  const week = {
    0: '日',
    1: '一',
    2: '二',
    3: '三',
    4: '四',
    5: '五',
    6: '六',
  };

  let dateString = fmt;

  if (/(Y+)/.test(dateString)) {
    dateString = dateString.replace(RegExp.$1, (`${date.getFullYear()}`).substr(4 - RegExp.$1.length));
  }
  if (/(E+)/.test(dateString)) {
    // eslint-disable-next-line no-nested-ternary
    dateString = dateString.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? '星期' : '周') : '') + week[date.getDay()]);
  }

  // 毫秒数
  if (/(S)/.test(dateString)) {
    dateString = dateString.replace(RegExp.$1, `${date.getMilliseconds()}`);
  }

  Object.keys(o).forEach((prop) => {
    if (new RegExp(`(${prop})`).test(dateString)) {
      const value = `${o[prop]}`;
      dateString = dateString.replace(RegExp.$1, `00${value}`.substr(value.length));
    }
  });
  return dateString;
}

function formatTickTime(v) {
  const minutes = Math.floor(v / 60);
  const seconds = v % 60;
  const strs = [];
  if (minutes > 0) {
    strs.push(`${minutes}分`);
  }
  if (seconds > 0) {
    strs.push(`${seconds}秒`);
  }

  return strs.join('');
}

const BleOpStatusEnum = {
  // 初始状态，未init前
  NOOP: 'NOOP',
  // 蓝牙不可用
  BLE_DISABLED: 'BLE_DISABLED',
  // 蓝牙可用
  BLE_READY: 'BLE_READY',
  // 正在扫描
  SCANNING: 'SCANNING',
  // 停止扫描
  STOP_SCANNING: 'STOP_SCANNING',
  // 已发现设备
  DEVICE_FOUNDED: 'DEVICE_FOUNDED',
  // 正在连接
  CONNECTING: 'CONNECTING',
  // 已连接
  CONNECTED: 'CONNECTED',
  // 连接失败
  CONNECT_FAILED: 'CONNECT_FAILED',
  // 断开连接
  DISCONNECTED: 'DISCONNECTED',
  // 连接超时
  CONNECT_OVERTIME: 'CONNECT_OVERTIME',
  // 例如：正在测量
  OPERATING: 'OPERATING',
  // 例如：测量完成
  OPERATE_FINISHED: 'OPERATE_FINISHED',
  // 发生了错误
  ERROR_OCCURED: 'ERROR_OCCURED',
};

/**
 * 微信的本地日志功能，需要用户手动反馈才能拿到日志文件
 */
const logger = () => {
  const wxlogger =
    wx.getLogManager &&
    wx.getLogManager({
      level: 0,
    });
  const log = (...params) => {
    console.log(...params);
    wxlogger && wxlogger.log(...params);
  };
  return {
    log,
  };
};

function getDefaultDeviceData() {
  return {
    /**
     * 状态
     * 0: 未在跳绳
     * 1: 正在跳绳
     * 2: 跳绳暂停
     * 3: 跳绳结束
     */
    status: -1,
    /**
     * 模式
     * 0: 自由跳
     * 1: 倒计时
     * 2: 倒计数
     */
    mode: -1,
    /**
     * 跳绳设定
     * 倒计数: 设定的数量
     * 倒计时: 设定的时间（分钟）
     * 自由跳: 0
     */
    modeValue: 0,
    // 跳绳个数
    count: 0,
    // 跳绳时间（秒）
    tickTime: 0,
    /**
     * 屏幕状态
     * 1: 亮屏
     * 0: 未亮屏
     */ 
    screenStatus: -1,
    /**
     * 待机状态
     * 1: 待机
     * 0: 未待机
     */ 
    standbyStatus: -1,
    /**
     * 电池状态
     * 0: 0-5%
     * 1: 6-25%
     * 2: 26-50%
     * 3: 51-75%
     * 4: 76-100%
     */
    batteryStatus: -1,
  };
}

function getStatusText(status) {
  /**
   * 状态
   * 0: 未在跳绳
   * 1: 正在跳绳
   * 2: 跳绳暂停
   * 3: 跳绳结束
   */
  switch (status) {
    case 0:
      return '未在跳绳';
    case 1:
      return '正在跳绳';
    case 2:
      return '跳绳暂停';
    case 3:
      return '跳绳结束';
    default:
      return '未知状态';
  }
}

function getModeText(mode) {
  /**
   * 模式
   * 0: 自由跳
   * 1: 倒计时
   * 2: 倒计数
   */
  switch (mode) {
    case 0:
      return '自由跳';
    case 1:
      return '倒计时';
    case 2:
      return '倒计数';
    default:
      return '未知模式';
  }
}

function getModeValueText(mode, modeValue) {
  switch (mode) {
    case 0:
      return modeValue;
    case 1:
      return formatTickTime(modeValue);
    case 2:
      return `${modeValue}（个数）`;
    default:
      return modeValue;
  }
}

function getBatteryStatusText(batteryStatus) {
  /**
   * 电池状态
   * 0: 0-5%
   * 1: 6-25%
   * 2: 26-50%
   * 3: 51-75%
   * 4: 76-100%
   */
  switch (batteryStatus) {
    case 0:
      return '0-5%';
    case 1:
      return '6-25%';
    case 2:
      return '26-50%';
    case 3:
      return '51-75%';
    case 4:
      return '76-100%';
    default:
      return '--';
  }
}

function getStandbyStatusText(standbyStatus) {
  switch (standbyStatus) {
    case 0:
      return '否';
    case 1:
      return '是';
    default:
      return '--';
  }
}

function getVibrationStatusText(vibrationStatus) {
  switch (vibrationStatus) {
    case 0:
      return '关闭';
    case 1:
      return '开启';
    default:
      return '--';
  }
}

function getSoundStatusText(soundStatus) {
  switch (soundStatus) {
    case 0:
      return '关闭';
    case 1:
      return '开启';
    default:
      return '--';
  }
}

function getScreenStatusText(screenStatus) {
  switch (screenStatus) {
    case 0:
      return '否';
    case 1:
      return '是';
    default:
      return '--';
  }
}

function getDeviceDataText(deviceData) {
  const ret = {};
  Object.entries(deviceData).forEach(([k, v]) => {
    switch (k) {
      case 'status':
        ret[k] = getStatusText(v);
        break;
      case 'mode':
        ret[k] = getModeText(v);
        break;
      case 'modeValue':
        ret[k] = getModeValueText(deviceData.mode, v);
        break;
      case 'screenStatus':
        ret[k] = getScreenStatusText(v);
        break;
      case 'standbyStatus':
        ret[k] = getStandbyStatusText(v);
        break;
      case 'vibrationStatus':
        ret[k] = getVibrationStatusText(v);
        break;
      case 'soundStatus':
        ret[k] = getSoundStatusText(v);
        break;
      case 'batteryStatus':
        ret[k] = getBatteryStatusText(v);
        break;
      case 'tickTime': {

        ret[k] = formatTickTime(v);
        break;
      }
      case 'timestamp':
        ret[k] = formatTime(new Date(v), 'YYYY-MM-DD HH:mm:ss');
        break;
      default:
        ret[k] = v;
        break;
    }
  });

  return ret;
}

Page({

  /**
   * 页面的初始数据
   */
  data: {
    deviceId: '',
    connected: false,
    connecting: false,
    bleOpStatus: BleOpStatusEnum.NOOP,
    bleOpStatusText: '初始化中...',
    // 蓝牙可用状态
    bleEnableState: false,
    modeGroup: [
      {
        value: 0,
        name: '自由跳',
      },
      {
        value: 1,
        name: '倒计时（分钟）',
      },
      {
        value: 2,
        name: '倒计数（个数）',
      },
    ],
    fnGroup: [
      {
        value: 1,
        name: '声音',
        valueGroup: [
          {
            value: 1,
            name: '开',
          },
          {
            value: 0,
            name: '关',
          },
        ],
      },
      {
        value: 2,
        name: '震动',
        valueGroup: [
          {
            value: 1,
            name: '开',
          },
          {
            value: 0,
            name: '关',
          },
        ],
      },
    ],
    standbyTimeRadioValue: -1,
    hasReceiveddeviceData: false,
    deviceData: getDefaultDeviceData(),
    deviceDataText: getDeviceDataText(getDefaultDeviceData()),
    // 存储记录笔数
    offlineDataCount: 0,
    // 固件版本
    firmwareVersion: 0,
    // 内部型号
    modelId: '',
    mac: '',
    storedData: [
      // getDeviceDataText({
      //   index: 1,
      //   timestamp: Date.now() - 10000,
      //   mode: 0,
      //   modeValue: 0,
      //   coun: 10,
      //   tickTime: 30,
      // }),
      // getDeviceDataText({
      //   index: 2,
      //   timestamp: Date.now() - 20000,
      //   mode: 1,
      //   modeValue: 5,
      //   coun: 32,
      //   tickTime: 140,
      // }),
      // getDeviceDataText({
      //   index: 3,
      //   timestamp: Date.now() - 30000,
      //   mode: 2,
      //   modeValue: 100,
      //   coun: 66,
      //   tickTime: 300,
      // }),
    ],
    mode: 0,
    modeValue: 0,
    modeValueMin: 0,
    modeValueMax: 0,
    fnRadioGroupIndex: 0,
    fnValueRadioGroupIndex: 0,
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    /**
     * 判断相关权限是否开启, 根据需求放在合适的位置
     * locationEnabled 是否开启定位
     * locationAuthorized 是否授权定位(仅安卓需要,需要选择始终允许,不能选择询问,因为微信不会询问用户是否开启定位)
     * bluetoothEnabled 蓝牙是否开启
     */
    // const { locationAuthorized, locationEnabled, bluetoothEnabled } = wx.getSystemInfoSync();
    // if (!locationAuthorized || !locationEnabled || !bluetoothEnabled) {
    //   this.tip('请确认相关权限是否开启');
    //   setTimeout(() => {
    //     wx.navigateBack();
    //   }, 2000);
    // }

    // 初始化蓝牙
    this.bleApi = new QNMPPlugin({
      useSdk: false,
      logger: logger(), // 非必须，日志功能，最好有，方便排查问题，可以替换为客户自己的
      protocols: [RopeProtocol],
    });

    // 错误监听
    this.bleApi.onError = (err) => {
      this.updateBleOpStatus(BleOpStatusEnum.ERROR_OCCURED);
      console.error('捕捉到错误', err.detail);
      wx.showToast({
        title: `发生了错误.[error]: ${err.message}`,
        icon: 'error',
      })
    };

    // 初始化回调
    this.bleApi.onReady = ({
      bleEnableState, // 表示当前蓝牙是否为开启状态
    }) => {
      if (bleEnableState) {
        this.updateBleOpStatus(BleOpStatusEnum.BLE_READY);
        this.setData({ bleEnableState: true });
        // this.bleApi.startBleDeviceDiscovery();
      } else {
        console.log('蓝牙状态为关闭');
        this.updateBleOpStatus(BleOpStatusEnum.BLE_DISABLED);
      }
    };

    // 设置蓝牙监听事件
    this.bleApi.setBleEventListener(this.bleEventListener());

    // 初始化
    this.bleApi.init();
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
    if (this.bleApi) {
      this.bleApi.stop();
    }
  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  },

  updateBleOpStatus(status) {
    let text = '';
    switch (status) {
      case BleOpStatusEnum.NOOP:
        text = '初始化中...';
        break;
      case BleOpStatusEnum.BLE_DISABLED:
        text = '蓝牙不可用';
        break;
      case BleOpStatusEnum.BLE_READY:
        text = '请将手机靠近设备进行连接';
        break;
      case BleOpStatusEnum.SCANNING:
        text = '正在扫描设备';
        break;
      case BleOpStatusEnum.DEVICE_FOUNDED:
        text = '已发现设备';
        break;
      case BleOpStatusEnum.CONNECTING:
        text = '正在连接...';
        break;
      case BleOpStatusEnum.STOP_SCANNING:
        text = '停止扫描';
        break;
      case BleOpStatusEnum.CONNECTED:
        text = '已连接';
        break;
      case BleOpStatusEnum.CONNECT_FAILED:
        text = '连接设备失败';
        break;
      case BleOpStatusEnum.DISCONNECTED:
        text = '断开连接';
        break;
      case BleOpStatusEnum.CONNECT_OVERTIME:
        text = '连接超时';
        break;
      case BleOpStatusEnum.OPERATING:
        text = '已连接，接收数据···';
        break;
      case BleOpStatusEnum.ERROR_OCCURED:
        text = '发生了错误';
        break;
      default:
        break;
    }

    this.setData({
      bleOpStatus: status,
      bleOpStatusText: text,
    });
  },
 
  // 蓝牙相关事件回调
  bleEventListener() {
    /**
     * 监听扫描到设备的回调
     */
    const onBleDeviceFound = (device) => {
      // 测试时这里可过滤mac来方便连接
      // if (device.mac === 'FF:F2:00:06:1D:AB') {
      //   this.updateBleOpStatus(BleOpStatusEnum.DEVICE_FOUNDED);
      //   this.handleConnect(device);
      // }

      this.updateBleOpStatus(BleOpStatusEnum.DEVICE_FOUNDED);
      this.handleConnect(device);
    };

    /**
     * 监听蓝牙断开连接的回调
     */
    const onDisconnected = (device) => {
      this.updateBleOpStatus(BleOpStatusEnum.DISCONNECTED);
      this.setData({
        connected: false,
      });
      this.resetData();
      console.log('设备连接已断开', device);
    };

    /**
     * 监听蓝牙状态发生变化回调，连接成功或断开连接都会出触发
     */
    const onBluetoothEnableChange = ({ available }) => {
      console.log('onBluetoothEnableChange', available);
      this.setData({ bleEnableState: available });
      if (available) {
        this.updateBleOpStatus(BleOpStatusEnum.BLE_READY);
        // this.bleApi.startBleDeviceDiscovery();
      } else {
        this.updateBleOpStatus(BleOpStatusEnum.BLE_DISABLED);
      }
    };

    /**
     * 	监听设备连接成功回调
     */
    const onConnected = ({ deviceId }) => {
      this.updateBleOpStatus(BleOpStatusEnum.CONNECTED);
      const device = this.bleApi.getConnectedDevice(deviceId);
      console.log('设备已连接', device);
      this.setData({
        connected: true,
        connecting: false,
        deviceId,
        offlineDataCount: device.offlineDataCount,
        firmwareVersion: device.firmwareVersion,
        modelId: device.modelId,
        mac: device.mac,
      });
    };

    /**
     * 监听停止扫描的回调
     */
    const onStopDiscoveryDevice = () => {
      if (this.data.bleOpStatus !== BleOpStatusEnum.CONNECTING) {
        this.updateBleOpStatus(BleOpStatusEnum.STOP_SCANNING);
      }
    };

    /**
     * 监听开始扫描设备的回调
     */
    const onStartDiscoveryDevice = () => {
      this.updateBleOpStatus(BleOpStatusEnum.SCANNING);
    };

    /**
     * 连接超时
     */
    const onConnectOverTime = () => {
      this.updateBleOpStatus(BleOpStatusEnum.CONNECT_OVERTIME);
      this.setData({
        connecting: false,
      });
    }

    return {
      onBleDeviceFound,
      onDisconnected,
      onBluetoothEnableChange,
      onConnected,
      onStopDiscoveryDevice,
      onStartDiscoveryDevice,
      onConnectOverTime,
    };
  },

  async handleConnect(device) {
    const { connecting } = this.data;
    if (connecting) {
      console.log('当前正在连接，不再处理');
      return;
    }
    this.setData({ connecting: true });
    this.updateBleOpStatus(BleOpStatusEnum.CONNECTING);

    await this.bleApi.createBleConnection(device, this.deviceEventListener());
  },

  // 秤端相关事件回调
  deviceEventListener() {
    /**
     * 获取设备实时数据
     * 注意这个方法会在设备连接阶段一直回调
     */
    const onGetRealtimeData = (deviceData) => {
      // console.log('实时数据', deviceData);
      this.setData({
        deviceData,
        deviceDataText: getDeviceDataText(deviceData),
        hasReceiveddeviceData: true,
      });
    };

    /**
     * 获取存储数据
     */
    const onGetStoredData = ({ total, data }) => {
      console.log('onGetStoredData', '总记录数', total, '数据', data);
      const d = getDeviceDataText(data);
      const { storedData } = this.data;
      storedData.push(d);

      this.setData({
        storedData,
      });
    };

    /**
     * 设置模式结果
     */
    const onSetModeResult = (result) => {
      if (result) {
        wx.showToast({
          title: '设置模式成功',
          icon: 'success',
        })
      } else {
        wx.showToast({
          title: '设置模式失败',
          icon: 'error',
        })
      }
    };

    /**
     * 清空历史数据结果
     */
    const onClearStoredDataResult = (result) => {
      if (result) {
        wx.showToast({
          title: '清空历史数据成功',
          icon: 'success',
        })
      } else {
        wx.showToast({
          title: '清空历史数据失败',
          icon: 'error',
        })
      }
    };

    /**
     * 同步时间结果
     */
    const onSyncTimeResult = (result) => {
      if (result) {
        wx.showToast({
          title: '同步时间成功',
          icon: 'success',
        })
      } else {
        wx.showToast({
          title: '同步时间失败',
          icon: 'error',
        })
      }
    };

    /**
     * 设置功能结果
     */
    const onSetFnResult = (result) => {
      if (result) {
        wx.showToast({
          title: '设置功能成功',
          icon: 'success',
        })
      } else {
        wx.showToast({
          title: '设置功能失败',
          icon: 'error',
        })
      }
    };

    /**
     * 结束运动结果
     */
    const onFinishTrainingResult = (result) => {
      if (result) {
        wx.showToast({
          title: '已结束运动',
          icon: 'success',
        })
      } else {
        wx.showToast({
          title: '结束运动失败',
          icon: 'error',
        })
      }
    };

    return {
      onGetRealtimeData,
      onGetStoredData,
      onSetModeResult,
      onClearStoredDataResult,
      onSyncTimeResult,
      onSetFnResult,
      onFinishTrainingResult,
    };
  },

  onModeRadioGroupChange(e) {
   this.setData({
    mode: Number(e.detail.value),
   });

   switch (Number(e.detail.value)) {
     case 0:
       this.setData({
        modeValueMin: 0,
        modeValueMax: 0,
        modeValue: 0,
       });
       break;
    case 1:
      this.setData({
        modeValueMin: 1,
        modeValueMax: 99,
        modeValue: 5,
       });
       break;
    case 2:
      this.setData({
        modeValueMin: 50,
        modeValueMax: 9999,
        modeValue: 100,
       });
       break;
    default:
      break;
   }
  },

  onModeValueChange(e) {
    this.setData({
      modeValue: Number(e.detail.value),
    });
  },

  onFnRadioGroupChange(e) {
    this.setData({
     fnRadioGroupIndex: Number(e.detail.value),
     fnValueRadioGroupIndex: 0,
    });
  },

  onFnValueRadioGroupChange(e) {
    this.setData({
      fnValueRadioGroupIndex: Number(e.detail.value),
    });
  },

  /**
   * 设置跳绳模式
   * @param {number} mode 0: 自由跳；1: 倒计时；2: 倒计数
   * @param {number} modeValue 如果是倒计时模式，则传的是分钟设定，倒计数传数量设定，自由跳传0
   */
  async doSetMode() {
    if (this.bleApi) {
      console.info('设置跳绳模式', 'mode', this.data.mode, 'modeValue', this.data.modeValue);
      // 倒计时转为秒
      const modeValue = this.data.mode === 1 ? this.data.modeValue * 60 : this.data.modeValue;
      this.bleApi.callProtocolMethodAsync(this.data.deviceId, 'doSetMode', [this.data.mode, modeValue]);
    }
  },

  /**
   * 设置功能开关
   * 外部调用 qnble.callProtocolMethodAsync(deviceId, 'doSetFn', ...args)
   * @param {number} type 1: 声音设置；2: 震动设置；
   * @param {number} typeValue 0: 关闭； 1: 开启
   */
  async doSetFn() {
    if (this.bleApi) {
      const type = this.data.fnGroup[this.data.fnRadioGroupIndex].value;
      const typeValue = this.data.fnGroup[this.data.fnRadioGroupIndex].valueGroup[this.data.fnValueRadioGroupIndex].value;
      console.info('设置功能开关', 'type', type, 'typeValue', typeValue);
      this.bleApi.callProtocolMethodAsync(this.data.deviceId, 'doSetFn', [type, typeValue]);
    }
  },

  /**
   * 结束运动
   */
  async doFinishTraining() {
    if (this.bleApi) {
      this.bleApi.callProtocolMethodAsync(this.data.deviceId, 'doFinishTraining', []);
    }
  },

  /**
   * 通知设备下发存储数据
   */
  async doReadStoredData() {
    if (this.bleApi) {
      console.info('doReadStoredData');
      this.setData({
        storedData: [],
      });
      this.bleApi.callProtocolMethodAsync(this.data.deviceId, 'doReadStoredData');
    }
  },

  /**
   * 清空存储数据
   */
  async doClearStoredData() {
    if (this.bleApi) {
      this.bleApi.callProtocolMethodAsync(this.data.deviceId, 'doClearStoredData');
    }
    this.setData({
      storedData: [],
      offlineDataCount: 0,
    });
  },

  startClick() {
    if (this.bleApi) {
      this.bleApi.startBleDeviceDiscovery();
    }
  },

  stopClick() {
    if (this.bleApi) {
      this.bleApi.stop().then(() => {
        this.resetData();
      });
    }
  },

  resetData() {
    this.setData({
      deviceData: getDefaultDeviceData(),
      deviceDataText: getDeviceDataText(getDefaultDeviceData()),
      offlineDataCount: 0,
      firmwareVersion: 0,
      modelId: '',
      mac: '',
      storedData: [],
      hasReceiveddeviceData: false,
    });
  }
})